package com.easyj.admin.activiti.serviceimpl;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;



import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestParam;

import com.easyj.admin.activiti.image.CustomProcessDiagramGenerator;
import com.easyj.admin.activiti.service.ProcessImagetService;
import com.easyj.base.exception.ActivitiException;

@Service
public class ProcessImageServiceImpl implements ProcessImagetService{
	
	@Autowired
    private RepositoryService repositoryService;
	
	@Autowired
	private HistoryService  historyService;
	
	
    public String getDiagram( @RequestParam(value = "procinstId")String procinstId) throws ActivitiException{
    	InputStream imageStream=null;
    	try {	
 
	    	HistoricProcessInstance processInstance =  historyService.createHistoricProcessInstanceQuery().processInstanceId(procinstId).singleResult();
	    	
	        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
	       
	        List<HistoricActivityInstance> historicActivityInstances =  historyService.createHistoricActivityInstanceQuery().processInstanceId(procinstId).orderByHistoricActivityInstanceId().finished().asc().list();
	
	       
	      // 高亮已经执行流程节点ID集合
	      List<String> highLightedActivitiIds = new ArrayList<>();
	      for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
	          highLightedActivitiIds.add(historicActivityInstance.getActivityId());
	      }
	      
	      List<HistoricActivityInstance> curActivityInstances =  historyService.createHistoricActivityInstanceQuery().processInstanceId(procinstId).orderByHistoricActivityInstanceId().unfinished().asc().list();
	  	
	
	      List<String> currIds = new ArrayList<>();
	      for (HistoricActivityInstance activityInstance : curActivityInstances) {
	    	  currIds.add(activityInstance.getActivityId());
	      }
	      
	      List<HistoricActivityInstance> allActivityInstance=new ArrayList<HistoricActivityInstance>();
	     
	      allActivityInstance.addAll(historicActivityInstances);
	      allActivityInstance.addAll(curActivityInstances);
	       // 高亮流程已发生流转的线id集合
	      List<String> highLightedFlowIds = getHighLightedFlows(bpmnModel, allActivityInstance);
	      CustomProcessDiagramGenerator generator = new CustomProcessDiagramGenerator();
	      
	      imageStream = generator.generateDiagram(
	              bpmnModel,
	              highLightedActivitiIds,//所有活动过的节点，包括当前在激活状态下的节点
	              highLightedFlowIds,//活动过的线
	              currIds,
	              new ArrayList<String>(),
	              "宋体",
	              "宋体",
	              "宋体",
	             true,null);
	       
	        // 输出资源内容到相应对象
	        ByteArrayOutputStream result = new ByteArrayOutputStream();
	    	byte[] buffer = new byte[1024];
	    	int length;
	    	while ((length = imageStream.read(buffer)) != -1) {
	    		result.write(buffer, 0, length);
	    	}
	        String encodeStr = Base64.getEncoder().encodeToString(result.toByteArray());
	        return encodeStr;
    	}catch(Exception ex) {
    	  throw new ActivitiException(ex.getMessage(),ex);
      }finally{
    	  if(imageStream!=null) {
    		  try {
				imageStream.close();
			} catch (IOException e) {
				
			}
    	  }
      }
    }
    
    
    public InputStream showDiagram( @RequestParam(value = "procinstId")String procinstId) {
    	  InputStream imageStream=null;
    		
	      HistoricProcessInstance processInstance =  historyService.createHistoricProcessInstanceQuery().processInstanceId(procinstId).singleResult();
	    	
	       BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
	       
	       List<HistoricActivityInstance> historicActivityInstances =  historyService.createHistoricActivityInstanceQuery().processInstanceId(procinstId).orderByHistoricActivityInstanceId().asc().list();
	
	       
	      // 高亮已经执行流程节点ID集合
	      List<String> highLightedActivitiIds = new ArrayList<>();
	      for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
	          // 用默认颜色
	          highLightedActivitiIds.add(historicActivityInstance.getActivityId());
	      }
	
	      List<String> currIds = historicActivityInstances.stream()
	              .filter(item -> item.getEndTime()==null)
	              .map(HistoricActivityInstance::getActivityId).collect(Collectors.toList());
	
	     
	       // 高亮流程已发生流转的线id集合
	      List<String> highLightedFlowIds = getHighLightedFlows(bpmnModel, historicActivityInstances);
	      CustomProcessDiagramGenerator generator = new CustomProcessDiagramGenerator();
	      //设置RunningActivityIdList...
	      //generator.setRunningActivityIdList(currIds);
	      imageStream = generator.generateDiagram(
	              bpmnModel,
	              highLightedActivitiIds,//所有活动过的节点，包括当前在激活状态下的节点
	              highLightedFlowIds,//活动过的线
	              currIds,
	              new ArrayList<String>(),
	              "宋体",
	              "宋体",
	              "宋体",
	             true,null);
	      
	        return imageStream;
	        
    }
	
	
	 private  List<String> getHighLightedFlows(BpmnModel bpmnModel, List<HistoricActivityInstance> historicActivityInstances) {
	        // 高亮流程已发生流转的线id集合
	        List<String> highLightedFlowIds = new ArrayList<>();
	        // 全部活动节点
	        List<FlowNode> historicActivityNodes = new ArrayList<>();
	        // 已完成的历史活动节点
	        List<HistoricActivityInstance> finishedActivityInstances = new ArrayList<>();

	        for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
	            FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstance.getActivityId(), true);
	            historicActivityNodes.add(flowNode);
	            if (historicActivityInstance.getEndTime() != null) {
	                finishedActivityInstances.add(historicActivityInstance);
	            }
	        }

	        FlowNode currentFlowNode = null;
	        FlowNode targetFlowNode = null;
	        // 遍历已完成的活动实例，从每个实例的outgoingFlows中找到已执行的
	        for (HistoricActivityInstance currentActivityInstance : finishedActivityInstances) {
	            // 获得当前活动对应的节点信息及outgoingFlows信息
	            currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true);
	            List<SequenceFlow> sequenceFlows = currentFlowNode.getOutgoingFlows();

	            /**
	                                           * 遍历outgoingFlows并找到已已流转的 满足如下条件认为已已流转：
	             * 1.当前节点是并行网关或兼容网关，则通过outgoingFlows能够在历史活动中找到的全部节点均为已流转
	             * 2.当前节点是以上两种类型之外的，通过outgoingFlows查找到的时间最早的流转节点视为有效流转
	             */
	            if ("parallelGateway".equals(currentActivityInstance.getActivityType())
	                    || "inclusiveGateway".equals(currentActivityInstance.getActivityType())) {
	                // 遍历历史活动节点，找到匹配流程目标节点的
	                for (SequenceFlow sequenceFlow : sequenceFlows) {
	                    targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true);
	                    if (historicActivityNodes.contains(targetFlowNode)) {
	                        highLightedFlowIds.add(sequenceFlow.getId());
	                    }
	                }
	            } else {
	                List<Map<String, Object>> tempMapList = new ArrayList<>();
	                for (SequenceFlow sequenceFlow : sequenceFlows) {
	                    for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
	                        if (historicActivityInstance.getActivityId().equals(sequenceFlow.getTargetRef())) {
	                            Map<String, Object> map = new HashMap<>();
	                            map.put("highLightedFlowId", sequenceFlow.getId());
	                            map.put("highLightedFlowStartTime", historicActivityInstance.getStartTime().getTime());
	                            tempMapList.add(map);
	                        }
	                    }
	                }

	                if (!CollectionUtils.isEmpty(tempMapList)) {
	                    // 遍历匹配的集合，取得开始时间最早的一个
	                    long earliestStamp = 0L;
	                    String highLightedFlowId = null;
	                    for (Map<String, Object> map : tempMapList) {
	                        long highLightedFlowStartTime = Long.valueOf(map.get("highLightedFlowStartTime").toString());
	                        if (earliestStamp == 0 || earliestStamp == highLightedFlowStartTime) {
	                            highLightedFlowId = map.get("highLightedFlowId").toString();
	                            earliestStamp = highLightedFlowStartTime;
	                        }
	                    }

	                    highLightedFlowIds.add(highLightedFlowId);
	                }

	            }

	        }
	        return highLightedFlowIds;
	    }
	 
	 
	 

}
